package cn.wen.java.nio;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import org.mozilla.intl.chardet.nsDetector;
import org.mozilla.intl.chardet.nsICharsetDetectionObserver;

/**
 * Title：JCharDet文件 字符集 探测器
 * <p>
 * Description：JCharDet 是mozilla自动字符集探测算法代码的java移植，其官方主页为： http://jchardet.sourceforge.net/
 * <p>
 * Copyright：Copyright (c) 2010-2012
 * 
 * @author <a href="mailto:ct_wen@qq.com">ctwen</a>, 温承瑭
 * @version Revision：1.0 Date：2011/11/23 Description：初完成。
 *          <p>
 */
public final class FileCharsetDetector {

    /**
     * 探测 文件 字符集。
     * 
     * @return 文件编码，若无，则返回null
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static String getEncoding(File file) throws FileNotFoundException, IOException {
	return getEncoding(file, new nsDetector());
    }

    /**
     * 探测 文件 字符集。
     * 
     * @param file File对象实例
     * @param languageHint 语言提示区域代码 eg：1 : Japanese; 2 : Chinese; 3 : Simplified Chinese; 4 : Traditional Chinese; 5 : Korean; 6 : Dont know (default)
     * @return 文件编码，eg：UTF-8,GBK,GB2312形式，若无，则返回null
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static String getEncoding(File file, int languageHint) throws FileNotFoundException, IOException {
	return getEncoding(file, new nsDetector(languageHint));
    }

    /**
     * 探测 文件 字符集。
     * 
     * @param path 文件路径
     * @return 文件编码，eg：UTF-8,GBK,GB2312形式，若无，则返回null
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static String getEncoding(String path) throws FileNotFoundException, IOException {
	return getEncoding(new File(path));
    }

    /**
     * 探测 文件 字符集。
     * 
     * @param path 文件路径
     * @param languageHint 语言提示区域代码 eg：1 : Japanese; 2 : Chinese; 3 : Simplified Chinese; 4 : Traditional Chinese; 5 : Korean; 6 : Dont know (default)
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static String getEncoding(String path, int languageHint) throws FileNotFoundException, IOException {
	return getEncoding(new File(path), languageHint);
    }

    /**
     * 探测 文件 字符集。
     * 
     * @param file File对象实例
     * @param det Detector
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static String getEncoding(File file, nsDetector det) throws FileNotFoundException, IOException {
	final Result rs = new Result();

	// Set an observer...
	// The Notify() will be called when a matching charset is found.
	det.Init(new nsICharsetDetectionObserver() {
	    public void Notify(String charset) {
		rs.found = true;
		rs.encoding = charset;
	    }
	});

	byte[] buf = new byte[1024];
	int len;
	boolean done = false;
	boolean isAscii = true;

	InputStream imp = new BufferedInputStream(new FileInputStream(file));

	while ((len = imp.read(buf, 0, buf.length)) != -1) {
	    // Check if the stream is only ascii.
	    if (isAscii) isAscii = det.isAscii(buf, len);
	    // DoIt if non-ascii and not done yet.
	    if (!isAscii && !done) done = det.DoIt(buf, len, false);
	}

	imp.close();
	det.DataEnd();

	if (isAscii) {
	    rs.encoding = "ASCII";
	    rs.found = true;
	}

	if (!rs.found) {
	    String prob[] = det.getProbableCharsets();
	    if (prob.length > 0) {
		// 在没有发现情况下，则取第一个可能的编码
		rs.encoding = prob[0];
	    }
	    else {
		return null;
	    }
	}
	return rs.encoding;
    }

    private static class Result {
	/**
	 * 查找标识。
	 */
	private boolean found = false;

	/**
	 * 如果完全匹配某个字符集检测算法, 则该属性保存该字符集的名称. 否则(如二进制文件)其值就为默认值 null, 这时应当查询属性。
	 */
	private String encoding = null;
    }

}
